Repository navigation
feat: AI 톤 교정 서비스 (#65 2/3) - #86
Merged
Merged
Conversation
This was referenced Nov 10, 2026
oTAETAEo
previously approved these changes
Nov 12, 2026
Comment on lines
+57
to
+79
| private LanguageModelResult complete(AiToneCorrectCommand command, AiToneReserveResult reservation) { | ||
| LanguageModelRequest request = new LanguageModelRequest(ToneCorrectionPrompt.systemPrompt(command.style()), | ||
| ToneCorrectionPrompt.userMessage(command.text()), MAX_OUTPUT_TOKENS); | ||
| long startedAt = System.nanoTime(); | ||
| LanguageModelResult result; | ||
| try { | ||
| result = languageModelClient.complete(request); | ||
| } catch (LanguageModelTimeoutException e) { | ||
| logFailure(command, startedAt, e); | ||
| throw releaseAndFail(reservation, AiErrorCode.LANGUAGE_MODEL_TIMEOUT); | ||
| } catch (LanguageModelException e) { | ||
| logFailure(command, startedAt, e); | ||
| throw releaseAndFail(reservation, AiErrorCode.LANGUAGE_MODEL_FAILED); | ||
| } | ||
|
|
||
| boolean blocked = result.refused() || ToneCorrectionPrompt.isBlocked(result.text()); | ||
| log.info("AI 톤 교정 userId={} style={} outcome={} elapsedMs={} outputTokens={}", command.userId(), | ||
| command.style(), blocked ? "blocked" : "success", elapsedMillis(startedAt), result.outputTokens()); | ||
| if (blocked) { | ||
| throw releaseAndFail(reservation, AiErrorCode.INAPPROPRIATE_TEXT); | ||
| } | ||
| return result; | ||
| } |
Contributor
There was a problem hiding this comment.
해당 부분이 리뷰어가 중점으로 보면 좋을 부분인 것으로 이해했습니다 !
[중점] 반환이 세 경우에서만 일어나는지, 트랜잭션을 걸지 않은 판단, 로그에 남기는 값
반환이 세 경우에서만 일어나는지
시간 초과, 외부 오류, 차단에서만 반환하는 것 확인했습니다.
그 밖의 예외로 500이 나면 1회가 차감되는데, 의도하신 거라면 명세 비고에 "500은 차감"을 적어 두면 좋을 것 같습니다
트랜잭션을 걸지 않은 판단
좋습니당 AI 호출할 때 트랜잭션이 걸려 있으면 DB 커넥션까지 잡혀 있게 되는 문제로 이해해서 적절한 것 같습니다 !
로그에 남기는 값
좋은 것 같아요 ! 원문·교정 결과는 빼고 필요한 부분만 잘 남기고 있는 것 같습니다 👍
Contributor
Author
There was a problem hiding this comment.
짚어 주셔서 감사해요! 확인해 보니 외부 호출 쪽 예외는 거의 다 외부 오류로 감싸져서, 1회를 잡은 뒤 500이 나는 건 사실상 서버 버그 때문이더라구요. 저희 버그로 사용자 횟수가 줄어드는 건 맞지 않는 것 같아서, 명세에 적는 대신 예상 못 한 예외가 나도 1회를 되돌리도록 고쳤습니다!
반환하는 곳을 correct()의 catch 한 곳으로 모아서 이중 반환도 생기지 않게 했어요. 스택 구조라 수정은 #87에 올렸습니다 (8501137). 명세 22번 비고에도 "서버 내부 오류(500)도 미차감"으로 추가했어요!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
관련 이슈
작업 내용
① 준비 #85 위에 쌓았습니다 (다음은 ③ #87). ①이 병합되면 기준 브랜치를 develop으로 바꿉니다.
AiToneCorrectionCommandService.correct(AiToneCorrectCommand)→AiToneCorrectResult@Transactional" 규칙의 예외. 클래스 주석에 이유를 적음)UserQueryService.validateActive(없으면USER404_1)AiToneUsageCommandService.reserve(남은 횟수가 없으면AI429_1, 언어 모델을 부르지 않음)<text>로 감싼 원문, 출력 토큰 상한 6000release한 뒤 에러를 던짐refused)이거나 표식만 출력(앞뒤 공백 무시)하면AI422_1LanguageModelException이면AI502_1(출력 상한max_tokens로 끝난 경우 포함, 잘린 결과를 내보내지 않음)LanguageModelTimeoutException이면AI504_1TextWhitespace), 이어서KeyInfoChecker.compareusage는 다시 조회하지 않고 선점 결과로 만듦.remaining= 한도 − 선점 후 횟수,resetAt= 선점한 날짜의 다음 날 00:00AI429_1·예상 못 한 예외(500)에서는 반환하지 않음toString은 원문·결과 대신 길이와 핵심 정보 개수만 보임명세와 달라진 점
없음 (출력 토큰 상한 6000의 명세 수정은 ③ PR)
테스트
모키토 단위 테스트
<text>로 감싼 원문, 출력 상한 6000USER404_1, 선점·언어 모델 호출 안 함AI429_1, 언어 모델 호출·반환 안 함AI422_1, 외부 오류AI502_1, 시간 초과AI504_1, 셋 다 선점한 1회를 반환AI504_1)toString에 원문·결과·핵심 정보 값이 없음트랜잭션 밖에서 동작하는지는 ③ PR의 통합 테스트(실제 선점·반환)로 확인
확인 체크리스트
./gradlew build통과global공통 코드를 바꿨다면 디스코드에 공유함 (변경 없음)리뷰어에게
[중점] 반환이 세 경우에서만 일어나는지, 트랜잭션을 걸지 않은 판단, 로그에 남기는 값